import { compare } from '@/widgets'
import type { Feature, LineString, Polygon } from 'geojson'
import mapboxgl from 'mapbox-gl'
import BaseLayer from './base-layer'
import type { LineStyle } from './types'

export interface BaseLineLayerOption<T> {
  id: string
  name: string
  getFeature: (t: T) => Feature<LineString | Polygon>
  style: LineStyle
  visible?: boolean
  minZoom?: number
}

export default class BaseLineLayer<T> extends BaseLayer {
  private getFeature: (t: T) => Feature<LineString | Polygon>
  private style: LineStyle
  private minZoom: number | undefined
  constructor(opts: BaseLineLayerOption<T>, dat: T[] | undefined = undefined) {
    super(opts.id, opts.name, opts.visible !== false, dat?.map((e) => opts.getFeature(e)))
    this.getFeature = opts.getFeature
    this.style = this.makeStyle(opts.style)
    this.minZoom = opts.minZoom
  }

  public clearData() {
    this.repaint([])
  }

  public updateData(lst: T[] | undefined) {
    if (!lst || lst.length === 0) {
      this.repaint([])
      return
    }
    const fLst = lst.map((e) => this.getFeature(e))
    this.repaint(fLst)
  }

  public setStyle(style: LineStyle) {
    style = this.makeStyle(style)
    const origin = this.style
    this.style = style
    const { map, id } = this
    if (!map) {
      return
    }
    if (origin.lineColor !== style.lineColor) {
      map.setPaintProperty(id, 'line-color', style.lineColor)
    }
    if (origin.lineWidth !== style.lineWidth) {
      map.setPaintProperty(id, 'line-width', style.lineWidth)
    }
    if (origin.lineOpacity !== style.lineOpacity) {
      map.setPaintProperty(id, 'line-opacity', style.lineOpacity)
    }
    if (!compare(origin.lineDashArray, style.lineDashArray)) {
      map.setPaintProperty(id, 'line-dasharray', style.lineDashArray)
    }
  }

  protected makeMapBoxGLLayer(): Omit<mapboxgl.Layer, 'source'> {
    const { style } = this
    const paint: mapboxgl.LinePaint = {
      'line-color': style.lineColor,
      'line-width': style.lineWidth,
      'line-opacity': style.lineOpacity
    }
    if (style.lineDashArray) {
      paint['line-dasharray'] = style.lineDashArray
    }
    return {
      id: this.id,
      type: 'line',
      paint,
      minzoom: this.minZoom
    }
  }

  private makeStyle(s: LineStyle): LineStyle {
    return Object.assign({}, s)
  }
}
